package com.javawork.juc.readWriteLock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

/**
 * @author zhangxiaolu
 * @since 2023-02-19 23:24
 */
public class StampedLockDemo {

    static int number = 37;
    static StampedLock stampedLock = new StampedLock();

    public void write() {
        long stamp = stampedLock.writeLock();
        System.out.println(Thread.currentThread().getName() + "\t 写线程准备修改");
        try {
            number = number + 13;
        } finally {
            stampedLock.unlock(stamp);
        }
        System.out.println(Thread.currentThread().getName() + "\t 写线程结束修改");
    }

    // 悲观读，读未完成时无法获得写锁
    public void read() {
        long stamp = stampedLock.readLock();
        System.out.println(Thread.currentThread().getName() + "\t come in readLock code block, 4 seconds continue...");
        for (int i = 0; i < 3; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t 正在读取中。。。。");
        }
        try {
            int result = number;
            System.out.println(Thread.currentThread().getName() + "\t 获得成员变量result：" + result);
            System.out.println("写线程没有修改成功，读锁时写锁无法介入，传统的读写互斥");
        } finally {
            stampedLock.unlockRead(stamp);
        }
    }

    // 乐观读，读的过程中也允许获得写锁介入
    public void optimisticRead() {
        long l = stampedLock.tryOptimisticRead();
        int result = number;
        // 故意间隔4s，很乐观的认为读取中没有其他的线程修改过number值
        System.out.println("4s前stampedLock.validate方法值（true无修改，false有修改）" + "\t" + stampedLock.validate(l));
        for (int i = 0; i < 4; i++) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "\t正在读取。。。" + i + " 秒后stampedLock.validate方法值（true无修改，false有修改）"
                    + stampedLock.validate(l));
            if (!stampedLock.validate(l)) {
                System.out.println("有人修改过-------有写操作");
                l = stampedLock.readLock();
                try {
                    System.out.println("从乐观读升级为悲观读");
                    result = number;
                    System.out.println("重新悲观读后result ：" + result);
                } finally {
                    stampedLock.unlockRead(l);
                }
            }
            System.out.println(Thread.currentThread().getName() + "finally value :  " + result);
        }
    }

    public static void main(String[] args) {
        StampedLockDemo stampedLockDemo = new StampedLockDemo();

        new Thread(() -> {
            stampedLockDemo.optimisticRead();
        }, "readThread").start();

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "---come in");
            stampedLockDemo.write();
        }, "writeThread").start();

        // 传统版
        /*new Thread(() -> {
            stampedLockDemo.read();
        }, "readThread").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "---come in");
            stampedLockDemo.write();
        }, "writeThread").start();

        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        System.out.println(Thread.currentThread().getName() + "result  " + number);*/
    }
}
